##################################################################
# PVCS Adaptor for SNiFF+
#
# File Version:
# $Id: PVCS.py,v 1.19 1999/10/25 13:31:28 toni Exp $
#
# Authors:
# - Terry W. Loar
# - Martin Klaus
# - Peter Thoeny
# - Uwe Stieber
#
# Adapter History:
# - Revised from RCSTCL Adaptor -  8/19/96
# - Integrated with SNiFF+ - 9/4/96
# - 1.0 Bugfix, CrossPlatform support - 4/2/97
# - 1.1 Functionality for Updating Workspaces added.
# - 1.2 Bug with creating multiple archive files fixed.
#       Bug with mutilated archive names on Windows fixed.
# - 1.3 SNiFF+ will complain if there's no PVCS installed.
# - 1.4 Adapter translated from TCL to Python
# - 1.5b2 Made repository extension generic, so that an appended 
#       ",v" is used in case it exists, else default PVCS suffix 
#       "??v___" is used.
# - 1.6a1 Adapt mechanism of archive suffix calculation from PVCS
#		  using the default PVCS config file, all extension combinations
#		  are possible now
# - 1.6b1 Ready for Windows
# - 1.6b2 Ready for Unix (add symbolic link handling)
# - 1.6   DiffMerge bugfix
#         add auto name facility for branching
# - 1.6p1 Patch Level 1: fix bug on Windows in update WE functionality
#				(Working Env defined with Env Variabel and Env Variable contains Backslash)
# - 1.7b1 Set label functionality and dialog
#		  automatic merged Site- and UserMenus files
# - 1.7b2 Preferences Dialog
# - 1.7   config file location settings in Preferences Dialog
# - 1.7.1 bugfix for calculation of user profile dir on UNIX, use now $HOME/.sniffrc
# - 1.7.2 allow all PVCS labels, improve Set Label dialog,
#         fix file rename bug on UNIX
# - 1.7.3 fix problem with suffix rules like '+,v'
#         fix sitemenu merge problem (forgot lines with '^')
# - 1.8b1 change the Preference layout to default SNiFF+ Preferences layout
#         add information and debug settings to the preferences dialog
# - 1.8b2 fix problems regarding merging of SiteMenus and UserMenus file
#         fix problems regarding archive file matching with extensions like '+,v'
#		  fix unexpected behavior of Edit - Button, if a suffix rule isn't deleteable
#		  except environment variable VCSDEBUG, if set
# - 1.8b3 fix Break Lock bug and implement functionality for break ALL locks of one file
#		  add field for adapter specific subdirectory in PVCS Preferences Dialog
# - 1.8b4 add move label functionality
# - 1.8b5 catch exceptions of the 'os.remove' call
#		  fix 'wrong directory for temp file' bug
#		  fix wrong call for 'checkout with concurrent lock'
#		  improved (more secure) symbolic link handling
#		  all operations use the config file now for sure
# - 1.8b6 fix incorrect initialisiation of PvcsPreferencesDialog
#		  remove occurence of vcs.TMPERR
# - 1.8b7 use common searchPathLib instead of PVCSCommonHelp.extendModulePath
#		  moved SetLabelDialog and MoveLabelDialog functionality to common
#		  module VCSLabels and generalized it
#		  module VCSLabels check now if there are two changeset on on revision
#		  and prints out an error if true
# - 1.8b8 implemented a common calling interface to support different calling
#		  semantics. Currently supported are Local and Remote PVCS command line calls
#		  non public version
# - 1.8b9 public version of 1.8b8 with bugfixes
#		  fix adaptor crash if Pvcs4Sniff.cfg will copied the first time to the
#		  remote site
#		  fix problems with Diff_W_V and Diff_V_V on (only remote call interface)
#		  fix problems with updating symbollist by the configuration manager
#		  fix incorrect creation fo directive VCSDIR
# - 1.8b10 bugfix version for 1.8b9
#		   fix bug in calling semantic for Diff_V_V
#		   fix several bug for remote PVCS handling
#
# Limitation:
# - Comments and Descriptions MUST follow the PVCS syntax rules
#
# Notes:
# - Please report problems to sniff-support@takefive.co.at
#
##################################################################

# import some system services
import sys, os, regsub, string

# append PVCS module path to common search path
import searchPathLib
searchPathLib.extendModulePath('lib/python/Sniff/Pvcs')

# import common VCS interface
import vcs

# make some names directly available
from chmod import chmod
from vlog import Vlog
from vcs import TRUE, FALSE

# SNiFF+ graphical interface
from etgui import *

# import PVCS specific module
import PVCSCommonHelp
import PVCSConfigFile
import PVCSConfigFileReader
import PVCSConfigFileWriter
import PVCSConstants

# redefine the 'normpath' function pointer
# if possible
if PVCSConstants.__dict__.has_key('unixpath'):
	vcs.normpath=PVCSConstants.unixpath

if os.environ.has_key("SNiFF_CMVC_REMOTE_USER"):
	vcs.user = os.environ["SNiFF_CMVC_REMOTE_USER"]
 
 
# initialize Adapter with the SNiFF+ default config file
aPVCSConfigDataStore = PVCSConfigFile.PVCSConfigFile()
configFileName = string.translate(os.path.join(os.environ['SNIFF_DIR'], 'lib', 'python', 'Sniff', 'Pvcs', 'Pvcs4Sniff.cfg'), vcs.BACKSLASH2SLASH)
aPVCSConfigFile = PVCSConfigFileReader.PVCSConfigFileReader(configFileName, aPVCSConfigDataStore)
try:
	aPVCSConfigFile.analyseConfigFile()
except:
	ShowAlert(eAlertNote, "@B(PVCS)@B Error during analysing config file @B'%s'@B !" % configFileName)
aPVCSConfigFileWriter = PVCSConfigFileWriter.PVCSConfigFileWriter(aPVCSConfigFile.getConfigFileName())

# initialize Call Interface
from PVCSConstants import usedCallingInterface
from PVCSConstants import callWrapper
import CommonCallWrapper
 
if callWrapper == None and vcs.TEST:
	print "(@B@I%s@I@B) @BWarning:@B Requested alternativ call interface not available ! Use local calls !" % __name__
 
# list of file to delete in the destuctor (only Remote)
filesToDelete = []
 
##################################################################

# some debug output
if vcs.TEST:
	print "(PVCS) System module search path: %s" % sys.path
	print "(PVCS) configFileName: %s" % configFileName
	print "(PVCS) Known archive list:"
	print aPVCSConfigDataStore.printArchiveSuffixList()
	print "(PVCS) PVCS Prefs File: %s" % PVCSConstants.PVCSPrefsFileName
	print "(PVCS) Adapter specific subdirectory: %s" % PVCSConstants.AdapterSpecificSubDir

def printVCSVars():
	if vcs.TEST:
		print "(Pvcs)@B@g>>>@x printVCSVars@B"
		print "(Pvcs)\tvcs.repositoryFile = %s" % vcs.repositoryFile
		print "(Pvcs)\tvcs.brancheName = %s" % vcs.branchName
		print "(Pvcs)\tvcs.branchFlag = %d" % vcs.branchFlag
		print "(Pvcs)\tvcs.comment = %s" % vcs.comment
		print "(Pvcs)\tvcs.date = %s" % vcs.date
		print "(Pvcs)\tvcs.workingFile = %s" % vcs.workingFile
		print "(Pvcs)\tvcs.catDir = %s" % vcs.catDir
		print "(Pvcs)\tvcs.SSWE = %s" % vcs.SSWE
		print "(Pvcs)\tvcs.SSWS = %s" % vcs.SSWS
		print "(Pvcs)\tvcs.SOWS = %s" % vcs.SOWS
		print "(Pvcs)\tvcs.description = %s" % vcs.description
		print "(Pvcs)\tvcs.pid = %s" % vcs.pid
		print "(Pvcs)\tvcs.lockType = %s" % vcs.lockType
		print "(Pvcs)\tvcs.projectName = %s" % vcs.projectName
		print "(Pvcs)\tvcs.repositoryDir = %s" % vcs.repositoryDir
		print "(Pvcs)\tvcs.RCCSPath = %s" % vcs.RCCSPath
		print "(Pvcs)\tvcs.repositoryRoot = %s" % vcs.repositoryRoot
		print "(Pvcs)\tvcs.projectDir = %s" % vcs.projectDir
		print "(Pvcs)\tvcs.symbolName = %s" % vcs.symbolName
		print "(Pvcs)\tvcs.forceFlag = %d" % vcs.forceFlag
		print "(Pvcs)\tvcs.tmpFile = %s" % vcs.tmpFile
		print "(Pvcs)\tvcs.tmpDir = %s" % vcs.tmpDir
		print "(Pvcs)\tvcs.user = %s" % vcs.user
		print "(Pvcs)\tvcs.revision = %s" % vcs.revision
		print "(Pvcs)\tvcs.revision2 = %s" % vcs.revision2
		print "(Pvcs)\tvcs.workingDir = %s" % vcs.workingDir
		print "(Pvcs)\tvcs.privateRoot = %s" % vcs.privateRoot
		print "(Pvcs)\tvcs.sniffDir = %s" % vcs.sniffDir
		print "(Pvcs)\tvcs.OSTempDir = %s" % vcs.OSTempDir
		print "(Pvcs)\tvcs.SYSTEM = %s" % vcs.SYSTEM
		print "(Pvcs)@B@r<<<@x printVCSVars@B"		
 
##################################################################

# some module LOCAL variables
_TMPCFG = 'temp.cfg'

_last_rep_file			= ''
_last_log_with_history	= FALSE
_last_log				= None

# ---- PVCS utils ------------------------------------

def create_cfg_file():
	global TMPCFG
	if usedCallingInterface == CommonCallWrapper.REMOTE:
		# REMOTE calls
		# check, if we have to rebuild TMPCFG at first
		if string.find(TMPCFG, vcs.privateRoot) == -1:
			# rebuild TMPCFG
			TMPCFG = vcs.joinpath(vcs.privateRoot, _TMPCFG)
		# open the config file
		cfg = open(TMPCFG, 'wb')
		remoteConfigFile = vcs.normpath(vcs.joinpath(vcs.privateRoot, os.path.basename(aPVCSConfigFile.getConfigFileName())))
		if os.path.exists(remoteConfigFile):
			mtimeRemoteConfigFile = vcs.get_mtime(vcs.get_stat(remoteConfigFile))
		else:
			mtimeRemoteConfigFile = 0
		if os.path.exists(aPVCSConfigFile.getConfigFileName()):
			mtimePvcsConfigFile = vcs.get_mtime(vcs.get_stat(aPVCSConfigFile.getConfigFileName()))
		else:
			import time
			mtimePvcsConfigFile = time.time()
		if vcs.TEST:
			import time
			print "(PVCS)\tmtimeRemoteConfigFile = %s" % time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(mtimeRemoteConfigFile))
			print "(PVCS)\tmtimePvcsConfigFile = %s" % time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(mtimePvcsConfigFile))
		if not os.path.exists(remoteConfigFile) or  mtimeRemoteConfigFile < mtimePvcsConfigFile:
			# copy SNiFF+ master config to remote site
			src = open(aPVCSConfigFile.getConfigFileName(), 'rb')
			dest = open(remoteConfigFile, 'wb')
			aLine = src.readline()
			while aLine != "":
				aLine = string.rstrip(aLine)
				dest.write(aLine)
				dest.write("\n")
				aLine = src.readline()
			dest.close()
			src.close()
		# write repository directory directive
		if callWrapper != None:
			cfg.write('Include %s\n' % callWrapper.translatePathnames(vcs.normpath(vcs.joinpath(vcs.privateRoot, os.path.basename(aPVCSConfigFile.getConfigFileName())))))
			cfg.write('VCSDIR %s\n' % callWrapper.translatePathnames(vcs.normpath(vcs.repositoryDir)))
		else:
			cfg.write('Include %s\n' % vcs.normpath(vcs.joinpath(vcs.privateRoot, os.path.basename(aPVCSConfigFile.getConfigFileName()))))
			cfg.write('VCSDIR %s\n' % vcs.normpath(vcs.repositoryDir))
		# should we lock the revision with concurrent lock ?
		if vcs.lockType=='C':
			cfg.write('MultiLock revision\n')
		# write the current user as ID
		if os.environ.has_key("SNiFF_CMVC_REMOTE_USER"):
			vcs.user = os.environ["SNiFF_CMVC_REMOTE_USER"]
		cfg.write('VCSID %s\n' % vcs.user)
		cfg.close()
	else:
		# LOCAL and SHAREDLIB calls
		# write as first the include statement for the SNiFF+
		# specific config file
		cfg = open(TMPCFG, 'w')
		cfg.write('Include %s\n' % vcs.normpath(aPVCSConfigFile.getConfigFileName()))
		# write repository directory directive
		cfg.write('VCSDIR %s\n' % vcs.normpath(vcs.repositoryDir))
		# should we lock the revision with concurrent lock ?
		if vcs.lockType=='C':
			cfg.write('MultiLock revision\n')
		# write the current user as ID
		if os.environ.has_key("SNiFF_CMVC_REMOTE_USER"):
			vcs.user = os.environ["SNiFF_CMVC_REMOTE_USER"]
		cfg.write('VCSID %s\n' % vcs.user)
		cfg.close()

 
# ---- log handling ----------------------------------

def log_without_history(use_cache=FALSE):
	if vcs.TEST: print "(PVCS)\t@B@g>>>@x log_without_history@B"
	global _last_rep_file, _last_log_with_history, _last_log
	if use_cache and _last_rep_file == vcs.repositoryFile:
		_last_log.reuse()
		if vcs.TEST: print "(PVCS)\t@B@r<<<@x log_without_history@B"
		return _last_log
	else:
		if string.find(vcs.repositoryFile, ' ') > 0:	# multiple files
			if vcs.TEST: print "(PVCS)\t@B@r<<<@x log_without_history@B"
			create_cfg_file()
			return Vlog(vcs.repositoryFile, vcs.workingFile, '-c%s -b' % TMPCFG)
		_last_rep_file = vcs.repositoryFile
		_last_log_with_history = FALSE
		create_cfg_file()
		_last_log = Vlog(vcs.repositoryFile, vcs.workingFile, '-c%s -b' % TMPCFG)
		_last_log.close()
		if not _last_log:
			_last_rep_file = ''
		if vcs.TEST: print "(PVCS)@B\t@r<<<@x log_without_history@B"
		return _last_log

def log_with_history(use_cache=FALSE):
	if vcs.TEST: print "(PVCS)\t@B@g>>>@x log_with_history@B"
	global _last_rep_file, _last_log_with_history, _last_log
	if use_cache and _last_log_with_history and _last_rep_file == vcs.repositoryFile:
		_last_log.reuse()
		if vcs.TEST: print "(PVCS)\t@B@r<<<@x log_with_history@B"
		return _last_log
	else:
		if string.find(vcs.repositoryFile, ' ') > 0:	# multiple files
			if vcs.TEST: print "(PVCS)\t@B@r<<<@x log_with_history@B"
			create_cfg_file()
			return Vlog(vcs.repositoryFile, vcs.workingFile, '-c%s' % TMPCFG)
		_last_rep_file = vcs.repositoryFile
		_last_log_with_history = TRUE
		create_cfg_file()
		_last_log = Vlog(vcs.repositoryFile, vcs.workingFile, '-c%s' % TMPCFG)
		_last_log.close()
		if not _last_log:
			_last_rep_file = ''
		if vcs.TEST: print "(PVCS)\t@B@r<<<@x log_with_history@B"
		return _last_log

##################################################################
# transLabel()
##################################################################
def transLabel(aLabel, transCharacters, replaceCharacters):	
	# translate german 'umlaute'
	tempLabel = aLabel
	tempLabel = string.replace(tempLabel, "ä", "ae")
	tempLabel = string.replace(tempLabel, "ö", "oe")
	tempLabel = string.replace(tempLabel, "ü", "ue")
	tempLabel = string.replace(tempLabel, "ß", "ss")
	# translate Label
	TRANSTABLE = string.maketrans(transCharacters, replaceCharacters)
	return string.translate(tempLabel, TRANSTABLE)


# ----------------------------------------------------------------
# ---- VCS commands ----------------------------------------------
# ----------------------------------------------------------------

##################################################################
# CheckOut()
#
# Perform the mapping of SNiFF+ to PVCS to check a file out of the 
# repository.
##################################################################
def CheckOut():
	if vcs.TEST: print "(PVCS)@B@g>>>@x Checkout@B"
	
	# be sure to be in the workfile dir
	currentDir=os.getcwd()
	if vcs.workingDir != currentDir:
		os.chdir(vcs.workingDir)
	create_cfg_file()

	if vcs.forceFlag:
		F = '-q'
	else:		
		F = '-qn'
	if vcs.revision:	
		R = '-r'+vcs.revision
	else:		
		R = ''
	path = vcs.joinpath(vcs.workingDir, vcs.workingFile)
	args = (TMPCFG, F, R, path)
	isSymbolicLink = vcs.FALSE
	symbolicFileName = ""
	# if using remote feature, then symbolic link handling must be different :-(
	remotemove = vcs.FALSE
	moveFileName = ""
	if sys.platform != 'win32':
		# PVCS follow the symbolic links by default and
		# do a mistake
		if os.path.islink(path):
			# yes, it is a link, remove it first
			isSymbolicLink = vcs.TRUE
			symbolicFileName = os.readlink(path)
			try:
				os.remove(path)
			except os.error, exc:
				ShowAlert(eAlertNote, "Can't remove symbolic link @B%s@B ! Break checkout operation, because command can't succeed ! Exception is 'os.error! and excpetion argument is '%s'" % (path, exc))
				if vcs.TEST: print "(PVCS)@B@r<<<@x Checkout (Return Code: %d)@B" % vcs.test(0)
				return vcs.test(0)
			except:
				ShowAlert(eAlertNote, "Can't remove symbolic link @B%s@B ! Break checkout operation, because command can't succeed ! Exception is unknown !" % path)
				if vcs.TEST: print "(PVCS)@B@r<<<@x Checkout (Return Code: %d)@B" % vcs.test(0)
				return vcs.test(0)
	# handling of symbolic links for remote PVCS feature
	if os.environ.has_key("PVCS_REMOTE_HOST") and os.path.exists(path):
		# PVCS follow the symbolic links by default and
		# do a mistake - REMOTE USE
		remotemove = vcs.TRUE
		moveFileName = vcs.joinpath(vcs.workingDir, 'checkoutfile.old')
		try:
			os.rename(path, moveFileName)
		except os.error, exc:
			ShowAlert(eAlertNote, "Can't backup file @B%s@B ! Break checkout operation, because command can't succeed ! Exception is 'os.error! and excpetion argument is '%s'" % (path, exc))
			if vcs.TEST: print "(PVCS)@B@r<<<@x Checkout (Return Code: %d)@B" % vcs.test(0)
			return vcs.test(0)
		except:
			ShowAlert(eAlertNote, "Can't rename file @B%s@B ! Break checkout operation, because command can't succeed ! Exception is unknown !" % path)
			if vcs.TEST: print "(PVCS)@B@r<<<@x Checkout (Return Code: %d)@B" % vcs.test(0)
			return vcs.test(0)
	if vcs.lockType == 'N':
		if vcs.TEST:
			print "(PVCS)\tCheckout with No Lock"
			print "(PVCS)\tcommand: @B@bget -c%s %s %s %s@x@B" % args
		if callWrapper == None:
			# call local command
			rc = vcs.system( 'get -c%s %s %s %s' % args)
		else:
			# call command through call wrapper
			rc = callWrapper.doCall("get", '-c%s %s %s %s' % args)
	elif vcs.lockType == 'E':
		if vcs.TEST:
			print "(PVCS)\tCheckout with Lock"
			print "(PVCS)\tcommand: @B@bget -c%s -l %s %s %s@x@B" % args
		if callWrapper == None:
			# call local command
			rc = vcs.system( 'get -c%s -l %s %s %s' % args)
		else:
			# call command through call wrapper
			rc = callWrapper.doCall("get", '-c%s -l %s %s %s' % args)
	else:
		if vcs.TEST:
			print "(PVCS)\tCheckout with Concurrent Lock"
			print "(PVCS)\tcommand: @B@bget -c%s %s %s %s@x@B" % args
		if callWrapper == None:
			# call local command
			rc = vcs.system( 'get -c%s %s %s %s' % args)
		else:
			# call command through call wrapper
			rc = callWrapper.doCall("get", '-c%s %s %s %s' % args)
		if rc == 0:
			chmod(path, 'u+w')
	vcs.lockType = ''
	if sys.platform != 'win32':
		# final handling of the symbolic link stuff
		if rc != 0 and isSymbolicLink == vcs.TRUE:
			# try to recreate the old symbolic link
			try:
				os.symlink(symbolicFileName, path)
			except:
				ShowAlert(eAlertNote, "@B@r(PVCS)!!!! Attention !!!! Could not recreate the symbolic link between %s and %s !!@x@B" % (symbolicFileName, path))
	# finalize handling of symbolic links for remote PVS feature
	if remotemove == vcs.TRUE:
		if rc != 0:
			# try to recreate the old symbolic link
			try:
				os.rename(moveFileName, path)
			except:
				ShowAlert(eAlertNote, "@B@r(PVCS)!!!! Attention !!!! Could not rename the backup-file %s to %s !!@x@B" % (moveFileName, path))
		else:
			try:
				vcs.rm_f(moveFileName)
			except:
				ShowAlert(eAlertNote, "@B@r(PVCS)!!!! Attention !!!! Could not remove the backup-file %s !!@x@B" % (moveFileName))
	if vcs.TEST: print "(PVCS)@B@r<<<@x Checkout (Return Code: %d)@B" % vcs.test(rc)
	return vcs.test(rc)


##################################################################
# CheckOutProject()
#
# CheckOutProject
##################################################################
def CheckOutProject():
	if vcs.TEST: print "(PVCS)@B@g>>>@x CheckoutProject@B"
	if vcs.TEST: print "(PVCS)@B@r<<<@x CheckoutProject@B"
	return TRUE


##################################################################
# CreateRepositoryFile()
#
# Perform the mapping of SNiFF+ to PVCS to check a file into the 
# repository for the first time.
##################################################################
def CreateRepositoryFile():
	if vcs.TEST: print "(PVCS)@B@g>>>@x CreateRepositoryFile@B"
	# be sure to be in the workfile dir
	currentDir=os.getcwd()
	if vcs.workingDir != currentDir:
		os.chdir(vcs.workingDir)
	create_cfg_file()

	if vcs.symbolName:
		S = '-v"'+transLabel(vcs.symbolName, ' :*"', '____')+'"'
	else:
		S = ''
	if vcs.lockType == 'E':
		L = '-l'
	else:
		L = '-u'
	if vcs.revision:
		R = '-r'+vcs.revision
	else:
		R = ''
	if vcs.description == '':
		description = '*** empty description ***'
	else:
		description = vcs.escape_quotes(vcs.description)
	path = vcs.joinpath(vcs.workingDir, vcs.workingFile)
	comment = vcs.escape_quotes(vcs.comment)
	args = (TMPCFG, L, comment, description, R, S, path)
	if vcs.TEST:
		print '(PVCS)\tcommand: @B@bput -c%s -q -f %s -m"%s" -t"%s" %s %s %s@x@B' % args
	if callWrapper == None:
		# call local command
		rc = vcs.system('put -c%s -q -f %s -m"%s" -t"%s" %s %s %s' % args)
	else:
		# call command through call wrapper
		rc = callWrapper.doCall("put", '-c%s -q -f %s -m"%s" -t"%s" %s %s %s' % args)
	if vcs.TEST: print "(PVCS)@B@r<<<@x CreateRepositoryFile (Return Code: %d)@B" % vcs.test(rc)
	return vcs.test(rc)


##################################################################
# CheckIn()
#
# Perform the mapping of SNiFF+ to PVCS to check a file into the
# repository.
##################################################################
def CheckIn():
	if vcs.TEST: print "(PVCS)@B@g>>>@x CheckIn@B"
	# be sure to be in the workfile dir
	currentDir=os.getcwd()
	if os.environ.has_key("SNiFF_CMVC_REMOTE_USER"):
		vcs.user = os.environ["SNiFF_CMVC_REMOTE_USER"]
	if vcs.workingDir != currentDir:
		os.chdir(vcs.workingDir)
	create_cfg_file()

	# check the lock status
	if IsLockedBy():
		# validate the lock for automatic branching
		log = log_with_history(TRUE)
		headRev = log.head_rev()
		lockedRev = GetLockedRev()
		if vcs.TEST:
			print "(PVCS)\t@BheadRev = @r%s@x@B" % headRev
			print "(PVCS)\t@BlockedRev = @r%s@x@B" % lockedRev
			print GetSymbolList()
			print "branches: ",
			print log.allBranchList
		if lockedRev != headRev:
			# might be a branch ?
			isOk = 0
			for aBranch in log.allBranchList:
				aBranchRev = log.searchNewestRevisionFor("%s" % aBranch + ".*")
				if lockedRev == aBranchRev:
					isOk = 1
			if isOk == 0:
				# non tip revision locked, PVCS force branch automatically
				import time
				currentTime = time.strftime("%d/%m/%Y_%H-%M-%S", time.localtime(time.time()))
				autoBranchName = vcs.user + "_" + currentTime
				if vcs.TEST:
					print "(PVCS)\t@BautoBranchName = @r%s@x@B" % autoBranchName
				answer = ShowAlert(eAlertQuestion, "User @B%s@B locked a non tip revision '@B%s@B' ! Creating automatic branch by PVCS with name '@B%s@B' !\nIs that ok ?" % (vcs.user, lockedRev, autoBranchName))
				if answer == 2:
					# YES button pressed
					vcs.branchFlag = 1
					vcs.branchName = "SNIFF_BRANCH_" + autoBranchName
				if answer == 3:
					# NO button pressed
					ShowAlert(eAlertNote, "Checkin aborted !")
					if vcs.TEST: print "(PVCS)@B@r<<<@x CheckIn (Return Code: 1)@B"
					return 1
	else:
		if not vcs.branchFlag:
			# show alert
			ShowAlert(eAlertNote, "No lock set by User @B%s@B!\nCheckin aborted !" % vcs.user)
			if vcs.TEST: print "(PVCS)@B@r<<<@x CheckIn (Return Code: 1)@B"
			return 1
	if vcs.lockType=='E':
		L = '-l'
	else:
		L = '-u'
	if vcs.revision:
		R = '-r'+vcs.revision
	else:
		R = ''
	if vcs.TEST:
		print "(PVCS)\trevision: @B@r%s@x@B" % vcs.revision
	path = vcs.joinpath(vcs.workingDir,vcs.workingFile)
	comment = vcs.escape_quotes(vcs.comment)
	if vcs.branchFlag:
		if vcs.TEST: print "(PVCS)\tforce new branch"
		# first lock revision
		args = (TMPCFG, PVCSConstants.getTempFile(), vcs.revision, path)
		if vcs.TEST:
			print "(PVCS)\tcommand: @B@bvcs -c%s -q -xe%s -l%s %s@x@B" % args
		if callWrapper == None:
			# call local command
			vcs.system('vcs -c%s -q -xe%s -l%s %s' % args)
		else:
			# call command through call wrapper
			callWrapper.doCall("vcs_command", '-c%s -q -xe%s -l%s %s' % args)
		# check in, assign branchname
		args = (TMPCFG, L, comment, vcs.branchName, path)
		if vcs.TEST:
			print '(PVCS)\tcommand: @B@bput -c%s -q -f -fb %s -m"%s" -v%s %s' % args
			print "(PVCS)\tbranch Name: @B@r%s@x@B" % vcs.branchName
		if callWrapper == None:
			# call local command
			rc = vcs.system('put -c%s -q -f -fb %s -m"%s" -v%s %s' % args)
		else:
			# call command through call wrapper
			rc = callWrapper.doCall("put", '-c%s -q -f -fb %s -m"%s" -v%s %s' % args)
		# assign second version label
		if vcs.symbolName:
			args = (TMPCFG, '"'+transLabel(vcs.symbolName, ' :*"', '____')+'"', vcs.branchName, path)
			if vcs.TEST:
				print "(PVCS)\tcommand: @B@bvcs -c%s -q -v%s:%s %s@x@B" % args
			if callWrapper == None:
				# call local command
				vcs.system('vcs -c%s -q -v%s:%s %s' % args)
			else:
				# call command through call wrapper
				callWrapper.doCall("vcs_command", '-c%s -q -v%s:%s %s' % args)
	else:
		if vcs.TEST: print "(PVCS)\tno branching, usual checkin"
		if vcs.symbolName:  
			S = '-v"'+transLabel(vcs.symbolName, ' :*"', '____')+'"'
		else:	
			S = ''
		args = (TMPCFG, L, comment, R, S, path)
		if vcs.TEST:
			print '(PVCS)\tcommand: @B@bput -c%s -q -f %s -m"%s" %s %s %s@x@B' % args
		if callWrapper == None:
			# call local command
			rc = vcs.system('put -c%s -q -f %s -m"%s" %s %s %s' % args)
		else:
			# call command through call wrapper
			rc = callWrapper.doCall("put", '-c%s -q -f %s -m"%s" %s %s %s' % args)
	if vcs.TEST: print "(PVCS)@B@r<<<@x CheckIn (Return Code: %d)@B" % vcs.test(rc)
	return vcs.test(rc)


##################################################################
# Lock()
#
# Perform the mapping of SNiFF+ to PVCS to lock a file in the 
# repository and make the work file writeable.
##################################################################
def Lock():
	if vcs.TEST: print "(PVCS)@B@g>>>@x Lock@B"
	# be sure to be in the workfile dir
	currentDir=os.getcwd()
	if vcs.workingDir != currentDir:
		os.chdir(vcs.workingDir)
	create_cfg_file()

	path = vcs.joinpath(vcs.workingDir,vcs.workingFile)
	if vcs.TEST:
		print "(PVCS)\tpath = %s" % path
		print "(PVCS)\tcall: vcs -q -c%s -l%s %s" % (TMPCFG, vcs.revision, path)
	if callWrapper == None:
		# call local command
		rc = vcs.system('vcs -q -c%s -l%s %s' % (TMPCFG, vcs.revision, path))
	else:
		# call command through call wrapper
		rc = callWrapper.doCall("vcs_command", '-q -c%s -l%s %s' % (TMPCFG, vcs.revision, path))
	if rc == 0:
		chmod(path, 'u+w')
	if vcs.TEST:
		print "(PVCS)\tfunction return code: %d" % rc
		print "(PVCS)@B@r<<<@x Lock (Return Code: %d)@B" % vcs.test(rc)
	return vcs.test(rc)


##################################################################
# SetWorkFileReadOnly()
#
# Perform the mapping of SNiFF+ to Adaptor to make a workfile 
# read-only.
##################################################################
def SetWorkFileReadOnly():
	if vcs.TEST: print "(PVCS)@B@g>>>@x SetWorkFileReadOnly@B"
	path = vcs.joinpath(vcs.workingDir,vcs.workingFile)
	chmod(path, 'ugo-w')
	if vcs.TEST: print "(PVCS)@B@r<<<@x SetWorkFileReadOnly@B"
	return TRUE


##################################################################
# UpdateProject()
#
# 
##################################################################
def UpdateProject():
	if vcs.TEST: print "(PVCS)@B@g>>>@x UpdateProject@B"
	if vcs.TEST: print "(PVCS)@B@r<<<x UpdateProject@B"
	return TRUE


##################################################################
# UpdateFile()
#
# Perform the mapping of SNiFF+ to PVCS to update a file. Calls
# get, vdiff through sniffUpdateFile.PVCS.sh shell script
##################################################################
def UpdateFile():
	if vcs.TEST: print "(PVCS)@B@g>>>@x UpdateFile@B"
	create_cfg_file()
	if usedCallingInterface == CommonCallWrapper.REMOTE and callWrapper != None:
		#ShowAlert(eAlertNote, "With this version of the PVCS integration, synchronizing a file or project is @Bnot supported@B !")
		#return TRUE
		# copy the update script to the remote site
		updateScriptNameRemote = vcs.joinpath(vcs.privateRoot, 'sniffUpdateFile.PVCS.sh')
		if os.path.exists(updateScriptNameRemote):
			mtimeUpdateScriptRemote = vcs.get_mtime(vcs.get_stat(updateScriptNameRemote))
		else:
			mtimeUpdateScriptRemote = 0
		updateScriptNameLocal = vcs.joinpath(vcs.sniffDir, 'bin', 'sniffUpdateFile.PVCS.sh')
		if os.path.exists(updateScriptNameLocal):
			mtimeUpdateScriptLocal = vcs.get_mtime(vcs.get_stat(updateScriptNameLocal))
		else:
			mtimeUpdateScriptLocal = 0
		if vcs.TEST:
			import time
			print "(PVCS)\tmtimeUpdateScriptRemote: %s" % time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(mtimeUpdateScriptRemote))
			print "(PVCS)\tmtimeUpdateScriptLocal: %s" % time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(mtimeUpdateScriptRemote))
			print "(PVCS)\tupdateScriptNameRemote: %s" % updateScriptNameRemote
			print "(PVCS)\tupdateScriptNameLocal: %s" % updateScriptNameLocal
		if not os.path.exists(updateScriptNameRemote) or mtimeUpdateScriptRemote < mtimeUpdateScriptLocal:
			# copy update script to remote side
			src = open(updateScriptNameLocal, 'rb')
			dest = open(updateScriptNameRemote, 'wb')
			aLine = src.readline()
			while aLine != "":
				aLine = string.rstrip(aLine)
				dest.write(aLine)
				dest.write("\n")
				aLine = src.readline()
			dest.close()
			src.close()
		# write the start script (overwrite necessary every time !!!)
		startScriptName = vcs.joinpath(vcs.privateRoot, 'startUpdate.sh')
		cmd = vcs.joinpath(vcs.privateRoot, 'sniffUpdateFile.PVCS.sh')
		SSWS = regsub.gsub(vcs.DELIMITER, ' ', vcs.normpath(vcs.SSWS))
		SOWS = regsub.gsub(vcs.DELIMITER, ' ', vcs.normpath(vcs.SOWS))
		if vcs.revision:
			R = '-r %s' % vcs.revision
		else:
			R = ''
		args = (callWrapper.translatePathnames(cmd),
				callWrapper.translatePathnames(vcs.normpath(os.path.expandvars(vcs.workingDir))),
				callWrapper.translatePathnames(vcs.normpath(os.path.expandvars(vcs.catDir))), 
				callWrapper.translatePathnames(vcs.normpath(os.path.expandvars(vcs.workingFile))),
				callWrapper.translatePathnames(vcs.normpath(os.path.expandvars(vcs.repositoryDir))),
				R,
				callWrapper.translatePathnames(vcs.normpath(os.path.expandvars(SSWS))),
				callWrapper.translatePathnames(vcs.normpath(os.path.expandvars(SOWS))),
				vcs.UNIX,
				" ",
				'/dev/null',
				callWrapper.translatePathnames(vcs.normpath(TMPCFG)))
		if vcs.TEST:
			print '(PVCS)\targs = @B@b%s \"%s\" \"%s\" \"%s\" \"%s\" %s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"@x@B' % args
		# write the start file finally
		startFile = open(startScriptName, "wb")
		if startFile != None:
			startFile.write('%s \"%s\" \"%s\" \"%s\" \"%s\" %s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"' % args)
			startFile.write("\n");
			startFile.close()
			out = callWrapper.doCall("sh_getoutput", startScriptName)
			vcs.output(out)
		else:
			ShowAlert(eAlertNote, "Can't create or overwrite 'Synchronize File...' startup file @B%s@B ! Synchronize aborted !" % startScriptName)
			print "(PVCS Remote) Can't create or overwrite 'Synchronize File...' startup file @B%s@B ! Synchronize aborted !" % startScriptName
			if vcs.TEST: print "(PVCS)@B@r<<<@x UpdateFile@B"
			return FALSE
	else:
		# run the update locally
		cmd = vcs.joinpath(vcs.sniffDir, 'bin', 'sniffUpdateFile.PVCS.sh')
		os.environ['SNIFF_DIR'] = vcs.normpath(vcs.sniffDir) # putenv
		SSWS = regsub.gsub(vcs.DELIMITER, ' ', vcs.normpath(vcs.SSWS))
		SOWS = regsub.gsub(vcs.DELIMITER, ' ', vcs.normpath(vcs.SOWS))
		if vcs.revision:
			R = '-r %s' % vcs.revision
		else:
			R = ''
		args = (cmd,
				vcs.normpath(os.path.expandvars(vcs.workingDir)),
				vcs.normpath(os.path.expandvars(vcs.catDir)), 
				vcs.normpath(os.path.expandvars(vcs.workingFile)),
				vcs.normpath(os.path.expandvars(vcs.repositoryDir)),
				R,
				vcs.normpath(os.path.expandvars(SSWS)),
				vcs.normpath(os.path.expandvars(SOWS)),
				vcs.SYSTEM,
				" ",
				vcs.NULLDEV,
				vcs.normpath(TMPCFG))
		if vcs.TEST: print '(PVCS)\targs = @B@b%s \"%s\" \"%s\" \"%s\" \"%s\" %s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"@x@B' % args
		out = vcs.getoutput('%s \"%s\" \"%s\" \"%s\" \"%s\" %s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"' % args)
		vcs.output(out)
	if vcs.TEST: print "(PVCS)@B@r<<<@x UpdateFile@B"
	return TRUE


##################################################################
# Unlock()
#
# Perform the mapping of SNiFF+ to PVCS to unlock a file in the 
# repository and make the work file read-only.
##################################################################
def Unlock():
	if vcs.TEST: print "(PVCS)@B@g>>>@x Unlock@B"
	# be sure to be in the workfile dir
	currentDir=os.getcwd()
	if vcs.workingDir != currentDir:
		os.chdir(vcs.workingDir)
	if os.environ.has_key("SNiFF_CMVC_REMOTE_USER"):
		vcs.user = os.environ["SNiFF_CMVC_REMOTE_USER"]
	create_cfg_file()

	args = (TMPCFG, vcs.revision, vcs.user, vcs.repositoryFile )
	if vcs.TEST: print "(PVCS)\targs = -c%s -r%s -u:%s %s" % args
	if callWrapper == None:
		# call local command
		rc = vcs.system('vcs -q -c%s -r%s -u:%s %s' % args)
	else:
		# call command through call wrapper
		rc = callWrapper.doCall("vcs_command", '-q -c%s -r%s -u:%s %s' % args)
	if vcs.TEST: print "(PVCS)@B@r<<<@x Unlock (Return Code: %d)@B" % vcs.test(rc)
	return vcs.test(rc)


##################################################################
# BreakLock()
#
# Perform the mapping of SNiFF+ to PVCS to break the lock on a 
# user's version of a file.
##################################################################
def BreakLock():
	if vcs.TEST: print "(PVCS)@B@g>>>@x BreakLock@B"
	# be sure to be in the workfile dir
	currentDir=os.getcwd()
	if vcs.workingDir != currentDir:
		os.chdir(vcs.workingDir)
	create_cfg_file()

	if callWrapper == None:
		# call local command
		out = vcs.getoutput('vlog -c%s -q -bl %s' % (TMPCFG, vcs.repositoryFile))
	else:
		# call command through call wrapper
		out = callWrapper.doCall("vlog_command", '-c%s -q -bl %s' % (TMPCFG, vcs.repositoryFile))
	rc = 0
	if out:
		splittedList = string.split(out, vcs.NL)
		breakAllLocks = 0
		if len(splittedList) > 2 and not vcs.revision:
			answer = ShowAlert(eAlertQuestion, "The file @B@I%s@I@B  has more than one lock set. \
You didn't specify an explicit revision to unlock. Should all locks be broken ?" % vcs.workingFile)
			if answer == 2:
				# YES
				breakAllLocks = 1
		for line in splittedList:
			if vcs.TEST:
				print "(PVCS)\t@Bline: '@b%s@x'@B" % line
			splittedLine = string.split(line)
			if len(splittedLine) >= 5:
				file, delim, user, delim, rev = string.split(line)
				if not vcs.revision and len(splittedList) == 2:
					# use HEAD 
					revision = GetHead()
				else:
					if not vcs.revision:
						if breakAllLocks == 1:
							# use locked revision
							revision = rev
					else:
						revision = vcs.revision
				if vcs.TEST:
					print "(PVCS)\t@Brev: '@b%s@x'@B" % rev
					print "(PVCS)\t@Bvcs.revision: '@b%s@x'@B" % vcs.revision
					print "(PVCS)\t@Brevision: '@b%s@x'@B" % revision
				if rev == revision:
					args = (TMPCFG, rev, user, vcs.repositoryFile)
					if callWrapper == None:
						# call local command
						rc = vcs.system('vcs -c%s -q -r%s -u:%s %s' % args)
					else:
						# call command through call wrapper
						rc = callWrapper.doCall("vcs_command", '-c%s -q -r%s -u:%s %s' % args)
					if rc != 0:
						break
				if breakAllLocks == 0:
					break
	if vcs.TEST: print "(PVCS)@B@r<<<@x BreakLock (Return Code: %d)@B" % vcs.test(rc)
	return vcs.test(rc)


##################################################################
# DeleteVersion()
#
# Perform the mapping of SNiFF+ to PVCS to delete a revision of a 
# file in the repository. This does not revert subsequent revisions. 
# It simply removes the record of the revision in the log.
##################################################################
def DeleteVersion():
	if vcs.TEST: print "(PVCS)@B@g>>>@x DeleteVersion@B"
	# be sure to be in the workfile dir
	currentDir=os.getcwd()
	if vcs.workingDir != currentDir:
		os.chdir(vcs.workingDir)
	if vcs.revision == '':
		log = log_without_history()
		if not log:
			return FALSE
		revision = log.head_rev()
	else:
		revision = vcs.revision

	create_cfg_file()
	if callWrapper == None:
		# call local command
		rc = vcs.system('vdel -c%s -q -r%s %s' % (TMPCFG, revision, vcs.repositoryFile))
	else:
		# call command through call wrapper
		rc = callWrapper.doCall("vdel", '-c%s -q -r%s %s' % (TMPCFG, revision, vcs.repositoryFile))
	if vcs.TEST: print "(PVCS)@B@r<<<@x DeleteVersion (Return Code: %d)@B" % vcs.test(rc)
	return vcs.test(rc)


##################################################################
# SetDescription()
#
# Perform the mapping of SNiFF+ to PVCS to specify the description 
# of  a version of a file in the repository.
##################################################################
def SetDescription():
	if vcs.TEST: print "(PVCS)@B@g>>>@x SetDescription@B"
	# be sure to be in the workfile dir
	currentDir=os.getcwd()
	if vcs.workingDir != currentDir:
		os.chdir(vcs.workingDir)

	description = vcs.escape_quotes(vcs.description)
	create_cfg_file()
	if callWrapper == None:
		# call local command
		rc = vcs.system('vcs -c%s -q -t"%s" %s' % (TMPCFG, description, vcs.repositoryFile))
	else:
		# call command through call wrapper
		rc = callWrapper.doCall("vcs_command", '-c%s -q -t"%s" %s' % (TMPCFG, description, vcs.repositoryFile))
	if vcs.TEST: print "(PVCS)@B@r<<<@x SetDescription (Return Code: %d)@B" % vcs.test(rc)
	return vcs.test(rc)


##################################################################
# SetSymbol()
#
# Perform the mapping of SNiFF+ to PVCS to associate a symbol with 
# the version of a file in the repository. Overwrite existing 
# symbol, if any.
##################################################################
def SetSymbol():
	if vcs.TEST: print "(PVCS)@B@g>>>@x SetSymbol@B"
	# be sure to be in the workfile dir
	currentDir=os.getcwd()
	if vcs.workingDir != currentDir:
		os.chdir(vcs.workingDir)

	if vcs.forceFlag:
		F = '-q'
	else:
		F = '-qn'
	V = string.strip(vcs.revision) # revision sometimes ends with newline
	create_cfg_file()
	args = (TMPCFG, F, transLabel(vcs.symbolName, ' :*"', '____'), V, vcs.repositoryFile)
	if callWrapper == None:
		# call local command
		rc = vcs.system('vcs -c%s %s -v"%s":%s %s' % args)
	else:
		# call command through call wrapper
		rc = callWrapper.doCall("vcs_command", '-c%s %s -v"%s":%s %s' % args)
	if vcs.TEST: print "(PVCS)@B@r<<<@x SetSymbol (Return Code: %d)@B" % vcs.test(rc)
	return vcs.test(rc)


##################################################################
# DeleteSymbol()
#
# Perform the mapping of SNiFF+ to PVCS to disassociate a symbol 
# from the version of a file in the repository.
##################################################################
def DeleteSymbol():
	if vcs.TEST: print "(PVCS)@B@g>>>@x DeleteSymbol@B"
	# be sure to be in the workfile dir
	currentDir=os.getcwd()
	if vcs.workingDir != currentDir:
		os.chdir(vcs.workingDir)

	create_cfg_file()
	args = (TMPCFG, '"'+transLabel(vcs.symbolName, ' :*"', '____')+'"', vcs.repositoryFile )
	if callWrapper == None:
		# call local command
		rc = vcs.system('vcs -c%s -q -v%s:delete %s' % args)
	else:
		# call command through call wrapper
		rc = callWrapper.doCall("vcs_command", '-c%s -q -v%s:delete %s' % args)
	if vcs.TEST: print "(PVCS)@B@r<<<@x DeleteSymbol (Return Code: %d)@B" % vcs.test(rc)
	return vcs.test(rc)


##################################################################
# ChangeComment()
#
# Perform the mapping of SNiFF+ to PVCS to change a version's 
# comment in a file in the repository.
##################################################################
def ChangeComment():
	if vcs.TEST: print "(PVCS)@B@g>>>@x ChangeComment@B"
	# be sure to be in the workfile dir
	currentDir=os.getcwd()
	if vcs.workingDir != currentDir:
		os.chdir(vcs.workingDir)

	create_cfg_file()
	comment = vcs.escape_quotes(vcs.comment)
	args = (TMPCFG, vcs.revision, comment, vcs.repositoryFile )
	if callWrapper == None:
		# call local command
		rc = vcs.system('vcs -c%s -q -r%s -m"%s" %s' % args)
	else:
		# call command through call wrapper
		rc = callWrapper.doCall("vcs_command", '-c%s -q -r%s -m"%s" %s' % args)
	if vcs.TEST: print "(PVCS)@B@r<<<@x ChangeComment (Return Code: %d)@B" % vcs.test(rc)
	return vcs.test(rc)


##################################################################
# Description()
#
# Perform the mapping of SNiFF+ to PVCS to get the description text
# of a file in the repository.
#
##################################################################
def Description():
	if vcs.TEST: print "(PVCS)@B@g>>>@x Description@B"
	log = log_without_history(TRUE)
	if not log:
		return FALSE
	vcs.output(log.description)
	if vcs.TEST: print "(PVCS)@B@r<<<@x Description@B"
	return TRUE


##################################################################
# History()
#
# Perform the mapping of SNiFF+ to PVCS to get the version control 
# history of a file in the repository.
#
##################################################################
def History():
	if vcs.TEST: print "(PVCS)@B@g>>>@x History@B"
	log = log_with_history(FALSE)
	if not log:
		return FALSE
	vcs.output(log.history_str())
	if vcs.TEST: print "(PVCS)@B@r<<<@x History@B"
	return TRUE


##################################################################
# Head()
#
# Perform the mapping of SNiFF+ to PVCS to show the HEAD revision 
# of the main branch of the repository.
##################################################################
def Head():
	if vcs.TEST: print "(PVCS)@B@g>>>@x Head@B"
	log = log_with_history(FALSE)
	if not log: 
		return FALSE
	vcs.output(log.head_rev())
	if vcs.TEST: print "(PVCS)@B@r<<<@x Head@B"
	return TRUE

##################################################################
# GetHead()
#
# returns the HEAD revision as string
##################################################################
def GetHead():
	if vcs.TEST: print "(PVCS)@B@g>>>@x GetHead@B"
	log = log_with_history(FALSE)
	if not log: 
		return None
	if vcs.TEST: print "(PVCS)@B@r<<<@x GetHead@B"
	return log.head_rev()

##################################################################
# GetLockedRev()
#
# returns the locked revision as string
##################################################################
def GetLockedRev():
	if vcs.TEST: print "(PVCS)@B@g>>>@x GetLockedRev@B"
	create_cfg_file()
	if callWrapper == None:
		# call local command
		out = vcs.getoutput('vlog -c%s -q -bl%s %s' % (TMPCFG, vcs.user, vcs.repositoryFile ))
	else:
		# call command through call wrapper
		out = callWrapper.doCall("vlog_command", '-c%s -q -bl%s %s' % (TMPCFG, vcs.user, vcs.repositoryFile ))
	if out == '': 
		return None
	lockedRev = string.split(out)[4]
	if vcs.TEST: print "(PVCS)@B@r<<<@x GetLockedRev@B"
	return lockedRev

##################################################################
# SymbolList()
#
# Perform the mapping of SNiFF+ to PVCS to show a complete history 
# of a file with all its revisions and symbols.
##################################################################
def SymbolList():
	if vcs.TEST: print "(PVCS)@B@g>>>@x SymbolList@B"
	log = log_with_history(FALSE)
	out_list = []
	while log:
		out_list.append('\014%s' % log.work_file())
		out_list.append('HEAD: %s' % log.head_rev())
		symbols = log.symbolstr()
		if symbols:
			out_list.append(symbols)
		for rev in log.revision_list():
			out_list.append(string.join((rev.rev, rev.date, rev.author, rev.lines)))
		log.next()
	vcs.output(string.join(out_list, vcs.NL))
	if vcs.TEST: print "(PVCS)@B@r<<<@x SymbolList@B"
	return TRUE

##################################################################
# GetSymbolList()
#
# Perform the mapping of SNiFF+ to PVCS to show a complete history 
# of a file with all its revisions and symbols.
##################################################################
def GetSymbolList():
	if vcs.TEST: print "(PVCS)@B@g>>>@x GetSymbolList@B"
	log = log_with_history(TRUE)
	out_list = []
	while log:
		out_list.append('\014%s' % log.work_file())
		out_list.append('HEAD: %s' % log.head_rev())
		symbols = log.symbolstr()
		if symbols:
			out_list.append(symbols)
		for rev in log.revision_list():
			out_list.append(string.join((rev.rev, rev.date, rev.author, rev.lines)))
		log.next()
	if vcs.TEST: print "(PVCS)@B@r<<<@x GetSymbolList@B"
	return string.join(out_list, vcs.NL)

##################################################################
# RevisionOfSymbol()
#
# Perform the mapping of SNiFF+ to PVCS to show the revision 
# of a file that a symbol is associated with.
#
##################################################################
def RevisionOfSymbol():
	if vcs.TEST: print "(PVCS)@B@g>>>@x RevisionOfSymbol@B"
	log = log_without_history(TRUE)
	if not log: return FALSE
	if vcs.symbolName == 'HEAD':
		vcs.output(log.head_rev())
		return TRUE
	rev = ''
	symbollist = log.symbollist()
	if symbollist:
		if vcs.TEST: print symbollist
		for sym_def in symbollist:
			[sym_name, version] = string.split(sym_def,':')
			if sym_name == transLabel(vcs.symbolName, ' :*"', '____'):
				rev = string.lstrip(version)
				break
	if vcs.TEST: print "(PVCS)@B@r<<<@x RevisionOfSymbol@B"
	if rev:
		vcs.output(rev)
		return TRUE
	else:
		return FALSE


##################################################################
# HistoryOfRevision()
#
# Perform the mapping of SNiFF+ to PVCS to show the history of a 
# sprecific version of a file.
##################################################################
def HistoryOfRevision():
	if vcs.TEST: print "(PVCS)@B@g>>>@x HistoryOfRevision@B"
	log = log_with_history(TRUE)
	if not log: return FALSE
	rev = log.revision(vcs.revision)
	if not rev: return FALSE
	vcs.output(str(rev))
	if vcs.TEST: print "(PVCS)@B@r<<<@x HistoryOfRevision@B"
	return TRUE


##################################################################
# Comment()
#
# Perform the mapping of SNiFF+ to PVCS to show the commment for 
# the specific version of a file.
#
##################################################################
def Comment():
	if vcs.TEST: print "(PVCS)@B@g>>>@x Comment@B"
	log = log_with_history(TRUE)
	if not log: return FALSE
	rev = log.revision(vcs.revision)
	if not rev: return FALSE
	vcs.output(rev.log_message)
	if vcs.TEST: print "(PVCS)@B@r<<<@x Comment@B"
	return TRUE


##################################################################
# Lockers()
#
# Perform the mapping of SNiFF+ to PVCS to show the locker and the 
# version of a file.
##################################################################
def Lockers():
	if vcs.TEST: print "(PVCS)@B@g>>>@x Lockers@B"
	log = log_without_history(FALSE)
	out_list = []
	while log:
		out_list.append('%s %s' % (log.work_file(), log.lockers()))
		log.next()
	vcs.output(string.join(out_list, vcs.NL))
	if vcs.TEST: print "(PVCS)@B@r<<<@x Lockers@B"
	return TRUE

##################################################################
# IsLockedBy()
#
# Perform the mapping of SNiFF+ to PVCS to determine if a file is 
# locked by a specific user.
##################################################################
def IsLockedBy():
	if vcs.TEST: print "(PVCS)@B@g>>>@x IsLockedBy@B"

	create_cfg_file()
	if callWrapper == None:
		# call local command
		out = vcs.getoutput('vlog -c%s -q -bl%s %s' % (TMPCFG, vcs.user, vcs.repositoryFile ))
	else:
		# call command through call wrapper
		out = callWrapper.doCall("vlog_command", '-c%s -q -bl%s %s' % (TMPCFG, vcs.user, vcs.repositoryFile ))
	if vcs.TEST: print "(PVCS)@B@r<<<@x IsLockedBy@B"
	return out != ''


##################################################################
# IsLocked()
#
# Perform the mapping of SNiFF+ to PVCS to determine if a file is 
# locked by any user.
#
##################################################################
def IsLocked():
	if vcs.TEST: print "(PVCS)@B@g>>>@x IsLocked@B"
	create_cfg_file()
	if callWrapper == None:
		# call local command
		out = vcs.getoutput('vlog -c%s -q -bl %s' % (TMPCFG, vcs.repositoryFile ))
	else:
		# call command through call wrapper
		out = callWrapper.doCall("vlog_command", '-c%s -q -bl %s' % (TMPCFG, vcs.repositoryFile ))
	if vcs.TEST: print "(PVCS)@B@r<<<@x IsLocked@B"
	return out != ''


##################################################################
# IsDifferent()
#
# Perform the mapping of SNiFF+ to PVCS to check if there is 
# a difference between the current working file and a given version.
##################################################################
def IsDifferent():
	if vcs.TEST: print "(PVCS)@B@g>>>@x IsDifferent@B"
	create_cfg_file()

	path = vcs.joinpath(vcs.workingDir,vcs.workingFile)
	args = (TMPCFG, vcs.revision, vcs.repositoryFile, path)
	if callWrapper == None:
		# call local command
		rc = vcs.system('vdiff -c%s -q -T -r%s %s %s' % args)
	else:
		# call command through call wrapper
		rc = callWrapper.doCall("vdiff", '-c%s -q -T -r%s %s %s' % args)
	if vcs.TEST: print "(PVCS)@B@r<<<@x IsDifferent@B"
	return vcs.test(rc)


##################################################################
# DiffText_W_V()
#
# Perform the mapping of SNiFF+ to PVCS to compare the current 
# working file with a given version. Put the differences in 
# DeltaFile.
##################################################################
def DiffText_W_V():
	if vcs.TEST: print "(PVCS)@B@g>>>@x Diff_W_V@B"
	# be sure to be in the workfile dir
	currentDir=os.getcwd()
	if vcs.workingDir != currentDir:
		os.chdir(vcs.workingDir)

	repFile = vcs.normpath( vcs.repositoryFile )

	create_cfg_file()
	path = vcs.joinpath(vcs.workingDir, vcs.workingFile)
	vcs.tmpFile = vcs.tmpFile + '_' + vcs.pid
	args = (TMPCFG, vcs.revision2, repFile, vcs.tmpFile)
	if vcs.TEST:
		print "(PVCS)\trevision: @B@r%s@x@B" % vcs.revision2
		print "(PVCS)\trepFile : @B@r%s@x@B" % repFile
		print "(PVCS)\ttmpFile : @B@r%s@x@B" % vcs.tmpFile
	if callWrapper == None:
		# call local command
		rc = vcs.system('get -c%s -q -r%s "%s(%s)"' % args)
	else:
		# call command through call wrapper
		rc = callWrapper.doCall("get", '-c%s -q -r%s "%s(%s)"' % args)
	if rc==0:
		# add temporary file to the delete list
		filesToDelete.append(vcs.tmpFile)
		# call the diff
		args = (path, vcs.normpath(vcs.tmpFile))
		if callWrapper == None:
			# call local command
			out = vcs.getoutput('diff -b %s %s' % args)
		else:
			# call command through call wrapper
			out = callWrapper.doCall("diff", '-b %s %s' % args)
		vcs.output(out)
		if vcs.TEST: print "(PVCS)@B@r<<<@x Diff_W_V@B"
		return out == ''
	if vcs.TEST: print "(PVCS)@B@r<<<@x Diff_W_V@B"
	return TRUE


##################################################################
# DiffText_V_V()
#
# Perform the mapping of SNiFF+ to PVCS to compare two revisions 
# of an archived file. Put the differences in DeltaFile.
##################################################################
def DiffText_V_V():
	if vcs.TEST: print "(PVCS)@B@g>>>@x Diff_V_V@B"
	# be sure to be in the workfile dir
	currentDir=os.getcwd()
	if vcs.workingDir != currentDir:
		os.chdir(vcs.workingDir)

	repFile = vcs.normpath( vcs.repositoryFile )

	create_cfg_file()
	revFile1 = vcs.tmpFile+'_'+vcs.revision
	revFile2 = vcs.tmpFile+'_'+vcs.revision2
	if vcs.TEST:
		print "(PVCS)\tvcs.revision = %s" % vcs.revision
		print "(PVCS)\tvcs.revision2 = %s" % vcs.revision2
		print "(PVCS)\tvcs.tmpFile = %s" % vcs.tmpFile
		print "(PVCS)\trevFile1 = %s" % revFile1
		print "(PVCS)\trevFile2 = %s" % revFile2
	args = (TMPCFG, vcs.revision, repFile, revFile1)
	if callWrapper == None:
		# call local command
		rc = vcs.system('get -c%s -q -r%s "%s(%s)"' % args)
	else:
		# call command through call wrapper
		rc = callWrapper.doCall("get", '-c%s -q -r%s "%s(%s)"' % args)
	if rc==0:
		# add temporary file to the delete list
		filesToDelete.append(revFile1)
		args = (TMPCFG, vcs.revision2, repFile, revFile2)
		if callWrapper == None:
			# call local command
			rc = vcs.system('get -c%s -q -r%s "%s(%s)"' % args)
		else:
			# call command through call wrapper
			rc = callWrapper.doCall("get", '-c%s -q -r%s "%s(%s)"' % args)
	if rc==0:
		# add temporary file to the delete list
		filesToDelete.append(revFile2)
		args = (revFile1, revFile2)
		if callWrapper == None:
			# call local command
			out = vcs.getoutput('diff -b %s %s' % args)
		else:
			# call command through call wrapper
			out = callWrapper.doCall("diff", '-b %s %s' % args)
		vcs.output(out)
		return out == ''
	if vcs.TEST: print "(PVCS)@B@r<<<@x Diff_V_V@B"
	return TRUE


##################################################################
# RepositoryDir()
#
# 
##################################################################
def RepositoryDir():
	if vcs.TEST: print "(PVCS)@B@g>>>@x RepositoryDir@B"
	repositoryDir=vcs.joinpath(vcs.RCCSPath, vcs.catDir, PVCSConstants.AdapterSpecificSubDir)
	vcs.output(repositoryDir)
	if vcs.TEST:
		print "(PVCS)\tcalculated directory: %s" % repositoryDir
		print "(PVCS)@B@r<<<@x RepositoryDir@B"
	return TRUE


##################################################################
# RepositoryFile()
#
# 
##################################################################
def RepositoryFile():
	if vcs.TEST: print "(PVCS)@B@g>>>@x RepositoryFile@B"

	# reload config file, if necessary
	aPVCSConfigFile.reload()

	# extract extension of workfile
	try:
		workFileExt = vcs.workingFile[string.rindex(vcs.workingFile, '.'):]
	except ValueError:
		workFileExt = '.'

	# calculate repository extension
	archiveExt = aPVCSConfigDataStore.calculateArchiveExtension(workFileExt)

	# build archive file name
	try:
		string.rindex(vcs.workingFile, '.')
		archiveFile = vcs.workingFile[:string.rindex(vcs.workingFile, '.')]
	except ValueError:
		archiveFile = vcs.workingFile
	archiveFile = archiveFile + archiveExt

	F = vcs.joinpath(vcs.repositoryDir, archiveFile)
	vcs.output(F)
	if vcs.TEST:
		print "(PVCS)\tcalculated Archive: %s" % F
		print "(PVCS)@B@r<<<@x RepositoryFile@B"
	return TRUE

##################################################################
# TempDir()
#
# 
##################################################################
def TempDir():
	if usedCallingInterface == CommonCallWrapper.REMOTE:
		vcs.output('/tmp')
	else:
		vcs.output(vcs.joinpath(vcs.OSTempDir, '.sniffdir2', 'PVCS_%s%s' % (vcs.user, vcs.pid)))
	return TRUE


##################################################################
# TempFile()
#
# 
##################################################################
def TempFile():
	vcs.output(vcs.joinpath(vcs.tmpDir, vcs.workingFile))
	return TRUE


##################################################################
# BranchDef()
#
# 
##################################################################
def BranchDef():
	vcs.output('I')
	return TRUE


##################################################################
# RepositoryCheckDef()
#
# 
##################################################################
def RepositoryCheckDef():
	vcs.output('I')
	return TRUE


##################################################################
# CheckRepositoryDir()
#
# 
##################################################################
def CheckRepositoryDir():
	return TRUE


##################################################################
# CheckRepositoryFile()
#
# 
##################################################################
def CheckRepositoryFile():
	return TRUE


##################################################################
# DateOfRepositoryFile()
#
# 
##################################################################
def DateOfRepositoryFile():
	return TRUE


##################################################################
# CreateRepositoryDir()
#
# Create a directory for a repository.
##################################################################
def CreateRepositoryDir():
	if vcs.TEST: print "(PVCS)@B@g>>>@x CreateRepositoryFile@B"
	rc = vcs.mkdir_p(vcs.repositoryDir, 0775)
	if vcs.TEST: print "(PVCS)@B@r<<<@x CreateRepositoryFile@B"
	return vcs.test(rc)


##################################################################
# TestTool()
#
# 
##################################################################
def TestTool():
	if usedCallingInterface == CommonCallWrapper.REMOTE:
		return vcs.TRUE
	else:
		return vcs.is_reachable('vcs')


##################################################################
# Constructor()
#
# 
##################################################################
def Constructor():
	if vcs.TEST: print "(PVCS)@B@g>>>@x Constructor@B"
	global TMPCFG
	if usedCallingInterface == CommonCallWrapper.LOCAL:
		if not os.path.isdir(vcs.tmpDir):
			vcs.mkdir_p(vcs.tmpDir)
	else:
		global filesToDelete
		filesToDelete = []
	TMPCFG = vcs.joinpath(vcs.tmpDir, _TMPCFG)
	if vcs.TEST: print "(PVCS)@B@r<<<@x Constructor@B"
	return TRUE


##################################################################
# Destructor()
#
# 
##################################################################
def Destructor():
	if vcs.TEST: print "(PVCS)@B@g>>>@x Destructor@B"
	if usedCallingInterface == CommonCallWrapper.LOCAL:
		if os.path.isdir(vcs.tmpDir):
			vcs.rm_fr(vcs.tmpDir)
	else:
		# may be, there is something in the delete list
		if len(filesToDelete) > 0 and callWrapper != None:
			for aFileToDelete in filesToDelete:
				if vcs.TEST:
					print "(PVCS)\ttry to delete %s..." % aFileToDelete
				rc = callWrapper.doCall("rm_f", "%s" % aFileToDelete)
				if rc == 0:
					print "(PVCS)\t\tsuccessful"
				else:
					print "(PVCS)\t\tfailed"
	if vcs.TEST: print "(PVCS)@B@r<<<@x Destructor@B"
	return TRUE

###### Custom Menu functions #####

##################################################################
# showPreferencesDialog()
##################################################################
def showPreferencesDialog():
	if vcs.TEST: print "(PVCS)@B@g>>>@x showPreferencesDialog@B"
	try:
		# ask for the list of suffix rules
		suffixRuleDict = aPVCSConfigDataStore.getArchiveSuffixList()
		# show the dialog
		import PVCSPrefsDialog
		if vcs.TEST:
			vcsDebug = 1
		else:
			vcsDebug = 0
		PVCSMasterConfig = PVCSCommonHelp.readValueFromPrefsFile(PVCSConstants.PVCSPrefsFileName, "PVCSMasterCfg"),
		PVCSProjectConfig = PVCSCommonHelp.readValueFromPrefsFile(PVCSConstants.PVCSPrefsFileName, "PVCSProjectCfg"),
		model = PVCSPrefsDialog.Show(
						suffixRuleDict,
						aPVCSConfigFile.getConfigFileName(),
						PVCSMasterConfig,
						PVCSProjectConfig,
						vcsDebug,
						PVCSConstants.TEST,
						PVCSConstants.VLOGTEST,
						aPVCSConfigDataStore.getDiagnostic(),
						aPVCSConfigDataStore.getQuiet(),
						aPVCSConfigDataStore.getSignOn(),
						PVCSConstants.AdapterSpecificSubDir,
					)
		if model != None:
			# write Prefs File
			PVCSCommonHelp.writePrefsFile(PVCSConstants.PVCSPrefsFileName, model)

			# set the global debug variables
			PVCSConstants.TEST = int(PVCSCommonHelp.readValueFromPrefsFile(PVCSConstants.PVCSPrefsFileName, "PVCSDebug"))
			PVCSConstants.VLOGTEST = int(PVCSCommonHelp.readValueFromPrefsFile(PVCSConstants.PVCSPrefsFileName, "VLOGDebug"))
			if PVCSCommonHelp.readValueFromPrefsFile(PVCSConstants.PVCSPrefsFileName, "VCSDebug") == "1":
				vcs.TEST = "1"
			else:
				vcs.TEST = ''
			if PVCSConstants.TEST:
				print "(PVCS) PVCSConstants.TEST = '%d'" % PVCSConstants.TEST
				print "(PVCS) PVCSConstants.VLOGTEST = '%d'" % PVCSConstants.VLOGTEST
				print "(PVCS) vcs.TEST = '%s'" % vcs.TEST

			# set the Adapter specific subdirectory
			PVCSConstants.AdapterSpecificSubDir = PVCSCommonHelp.readValueFromPrefsFile(PVCSConstants.PVCSPrefsFileName, "AdapterSubDir")

			try:
				# write the config File
				# add / delete include statements to SNiFF+ Master Config File

				# disabled at 22.06.1999 by USI
				#aPVCSConfigFileWriter.includeConfigFiles(model.GetValue("masterCFGFile"),
				#										model.GetValue("projectCFGFile"))

				# write diagnostic level to config file
				aPVCSConfigFileWriter.updateDiagnosticFlag(model.GetValue("Option_Diagnostic"))

				# write Quiet flag
				aPVCSConfigFileWriter.updateQuietFlag(model.GetValue("Option_Quiet"))

				# write SignOn flag to config file
				aPVCSConfigFileWriter.updateSignOnFlag(model.GetValue("Option_SignOn"))

				# write the suffix rules
				suffixRuleDict = model.GetValue("Suffix Rules")
				if vcs.TEST:
					print "(PVCS)\tgot following dictionary from dialog: @B@r",
					print suffixRuleDict,
					print "@x@B"

				# write changes to config file
				aPVCSConfigFileWriter.updateSuffixRules(suffixRuleDict)
			except PVCSConstants.PVCSErrorWritingConfigFile:
				pass
			# reload config file
			aPVCSConfigFile.forceReload()
	except:
		if vcs.TEST:
			print "(PVCS)@B@r<<<@x showPreferencesDialog (Exception)@B"
		import traceback
		traceback.print_exc()
		return
	if vcs.TEST: print "(PVCS)@B@r<<<@x showPreferencesDialog@B"
	return

##################################################################
# EOF
##################################################################
